package JUC.CompletableFuture;

import java.util.concurrent.*;

/**
 * @author CKC
 * @CreateTime 2022/6/7 20:35
 */
public class CompletableFutureAPIDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {

        //computeResultAndDealCompute();

        //extracted1();
        extracted2();

        //extracted3();

        //extracted4();
    }

    //对计算结果进行合并 thenCombine
    private static void extracted4() {

        CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t ----启动");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 10;
        });
        CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t ----启动");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 20;
        });

        System.out.println(completableFuture1.thenCombine(completableFuture2, Integer::sum).join());

        //or
        //System.out.println(CompletableFuture.supplyAsync(() -> {
        //    System.out.println(Thread.currentThread().getName() + "\t ----启动");
        //    try {
        //        TimeUnit.SECONDS.sleep(1);
        //    } catch (InterruptedException e) {
        //        e.printStackTrace();
        //    }
        //    return 10;
        //}).thenCombine(CompletableFuture.supplyAsync(() -> {
        //    System.out.println(Thread.currentThread().getName() + "\t ----启动");
        //    try {
        //        TimeUnit.SECONDS.sleep(2);
        //    } catch (InterruptedException e) {
        //        e.printStackTrace();
        //    }
        //    return 20;
        //}), Integer::sum).join());
    }

    //对计算速度进行选用 ： applyToEither
    private static void extracted3() {
        CompletableFuture<String> completableFutureA = CompletableFuture.supplyAsync(() -> {
            System.out.println("====  play A come in");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "play A";
        });

        CompletableFuture<String> completableFutureB = CompletableFuture.supplyAsync(() -> {
            System.out.println("====  play B come in");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "play B";
        });
        CompletableFuture<String> result = completableFutureA.applyToEither(completableFutureB, f -> {
            return f + " is winner";
        });
        System.out.println(result.join());

        //or

        //CompletableFuture<String> result1 = CompletableFuture.supplyAsync(() -> {
        //    System.out.println("====  play A come in");
        //    try {
        //        TimeUnit.SECONDS.sleep(2);
        //    } catch (InterruptedException e) {
        //        e.printStackTrace();
        //    }
        //    return "play A";
        //}).applyToEither(CompletableFuture.supplyAsync(() -> {
        //    System.out.println("====  play B come in");
        //    try {
        //        TimeUnit.SECONDS.sleep(1);
        //    } catch (InterruptedException e) {
        //        e.printStackTrace();
        //    }
        //    return "play B";
        //}), f -> f + " is winner");
        //System.out.println(result1.join());


    }

    //thenXxxxAsync 与 thenXxxx 区别
    private static void extracted2() {
        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        CompletableFuture.supplyAsync(() -> {
            System.out.println("111 " + Thread.currentThread().getName());
            return "abc";
        }, threadPool).thenRun(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("222 " + Thread.currentThread().getName());
        }).thenRun(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("333 " + Thread.currentThread().getName());
        }).thenRun(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("444 " + Thread.currentThread().getName());
        });
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        threadPool.shutdown();
    }

    private static void extracted1() {
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("111");
            return 1;
        }, threadPool).thenApply(f -> {
            int i = 10 / 0;
            System.out.println("222");
            return f + 2;
        }).thenApply(f -> {
            System.out.println("333");
            return f + 2;
        }).whenComplete((value, exception) -> {
            if (exception == null) {
                System.out.println("compute result:" + value);
            }
        }).exceptionally(exception -> {
            exception.printStackTrace();
            System.out.println(exception.getMessage());
            return null;
        });
        System.out.println("----------------------------");
        //handle 遇到异常还能继续向下执行
        CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("111");
            return 1;
        }, threadPool).handle((f, e) -> {
            int i = 1 / 0;
            System.out.println("222");
            return f + 2;
        }).handle((f, e) -> {
            System.out.println("333");
            return f + 2;
        }).whenComplete((value, exception) -> {
            if (exception == null) {
                System.out.println("compute result:" + value);
            }
        }).exceptionally(exception -> {
            exception.printStackTrace();
            System.out.println(exception.getMessage());
            return null;
        });


        threadPool.shutdown();
    }

    //获取计算结果和触发计算
    private static void computeResultAndDealCompute() {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "aa";
        });

        //System.out.println(completableFuture.get());
        //System.out.println(completableFuture.get(1,TimeUnit.SECONDS));
        //System.out.println(completableFuture.join());  与get() 一样的会阻塞
        //System.out.println(completableFuture.getNow("bb"));  当前没有获取到结果，则返回给定的值

        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(completableFuture.complete("completableValue") + "\t" + completableFuture.join()); //true	completableValue
    }
}
